/*
 * PopupPanel.java
 *
 * Created on 13 de Junho de 2007, 22:24
 */
package i3.ui;

import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.AbstractAction;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.Position.Bias;
import i3.ui.controller.MovingPane;
import i3.util.DefaultUndoManager;

/**
 *
 * @author  i30817
 */
public class PopupPanel extends javax.swing.JPanel {

    private MovingPane pane;
    private DefaultUndoManager undoRedo;
    private SliderChangeListener instance = new SliderChangeListener();
    private int lastInvocationIndex;

    private class SliderChangeListener implements ChangeListener {

        @Override
        public void stateChanged(ChangeEvent e) {

            if (jSlider1.getValueIsAdjusting()) {
                updatePercentage();
            } else {
                int requiredIndex = jSlider1.getValue();
                int index = pane.getIndex();

                //ignore
                if (requiredIndex == index) {
                    return;
                }
                //backward bias is easy since it doesn't end up in the same index unless
                //at the beginning of the document
                if (requiredIndex < index) {
                    int backIndex = pane.setWordIndex(requiredIndex, Bias.Backward);
                    if (backIndex > -1) {
                        updateWithoutListener(backIndex);
                    }
                    return;
                }
                //forward bias should move a whole word, not stay the same for word.length
                int actualIndex = index;
                while (actualIndex == index && requiredIndex <= pane.getLength()) {
                    actualIndex = pane.setWordIndex(requiredIndex++, Bias.Forward);
                }

                if (actualIndex > -1) {
                    updateWithoutListener(actualIndex);
                }
            }
        }
    }

    private class SliderMouseWheelSlide implements MouseWheelListener {

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            if (e.getWheelRotation() < 0) {
                pane.moveBackward();
            } else {
                pane.moveForward();
            }

            updateWithoutListener(pane.getIndex());
        }
    }

    private class ResetButtonAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            pane.setIndex(lastInvocationIndex);
            updateWithoutListener(lastInvocationIndex);
        }
    }

    /** Creates new form PopupPanel */
    public PopupPanel() {
        super();
        initComponents();
        jButton1.addActionListener(new ResetButtonAction());
        jSlider1.addMouseWheelListener(new SliderMouseWheelSlide());
        //Notification of ancestor visibility changes
        addHierarchyListener(new HierarchyListener() {

            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) == HierarchyEvent.SHOWING_CHANGED) {
                    if (isShowing()) {
                        lastInvocationIndex = pane.getIndex();
                        updateWithoutListener(lastInvocationIndex, pane.getLength());
                    } else if (pane.getIndex() != lastInvocationIndex) {
                        undoRedo.addEdit(new MovementUndoableEdit(lastInvocationIndex, pane.getIndex(), pane));
                    }
                }
            }
        });
    }

    public PopupPanel(MovingPane given, DefaultUndoManager u) {
        this();
        pane = given;
        undoRedo = u;
    }

    private void updatePercentage() {
        float percent = (pane.getLength() == 0) ? 0.0f : (float) (jSlider1.getValue()) / pane.getLength();
        percentLabel.setText(String.format("%.3g%%", percent * 100));
    }

    private void updateWithoutListener(int position) {
        jSlider1.removeChangeListener(instance);
        jSlider1.setValue(position);
        jSlider1.addChangeListener(instance);
        updatePercentage();
    }

    private void updateWithoutListener(int position, int maximum) {
        jSlider1.removeChangeListener(instance);
        jSlider1.setMaximum(maximum);
        jSlider1.setValue(position);
        jSlider1.addChangeListener(instance);
        updatePercentage();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jSlider1 = new javax.swing.JSlider();
        jLabel1 = new javax.swing.JLabel();
        jButton1 = new javax.swing.JButton();
        percentLabel = new javax.swing.JLabel();

        jLabel1.setText("Location:");

        jButton1.setText("Reset");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addGap(18, 18, 18)
                        .addComponent(percentLabel))
                    .addComponent(jSlider1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jButton1)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel1)
                            .addComponent(percentLabel))
                        .addGap(10, 10, 10)
                        .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(19, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JSlider jSlider1;
    private javax.swing.JLabel percentLabel;
    // End of variables declaration//GEN-END:variables
}
